home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #41 (Feb 89) / security code / Patrol.p < prev    next >
Text File  |  1988-11-29  |  14KB  |  580 lines

  1. UNIT  Patrol;
  2. {-------------------------------------------}
  3. (*
  4. ©1988 by Steve Seaquist. All rights reserved.
  5. Used by permission.  Use at your own risk.  
  6. No warranty is expressed or implied.  
  7.  
  8. This Macintosh virus-detecting program was 
  9. originally published and explained in the 
  10. February 1989 issue of MacTutor magazine.  
  11. Some aspects of its design are important to 
  12. security, and it uses some unusual 
  13. techniques, so please read the article.  
  14. *)
  15. {-------------------------------------------}
  16. INTERFACE
  17. USES
  18.   MemTypes,QuickDraw,OSIntf,ToolIntf,
  19.   PackIntf,Globals;
  20.  
  21. PROCEDURE  BuildDirname;
  22. PROCEDURE  InitPatrols;
  23. PROCEDURE  PatrolDirectories
  24.   (pOnly1Deep:BOOLEAN);
  25. PROCEDURE  PatrolEverything;
  26. PROCEDURE  PatrolFiles;
  27.  
  28. {*******************************************}
  29. IMPLEMENTATION
  30. {$R-}
  31.  
  32. CONST
  33.   kPatsInitd          = -12345;
  34.  
  35. TYPE
  36.   TOverlappingPBs     =
  37.     RECORD
  38.     CASE INTEGER OF
  39.     0:  (fPBRec:      HParamBlockRec);
  40.     1:  (fCPBRec:     CInfoPBRec);
  41.     END;
  42.  
  43. VAR
  44.   gAAPatImpl:         SignedByte;
  45.   gAppDirId:          LONGINT;
  46.   gAppVRefNum:        INTEGER;
  47.   gInitdFlag:         LONGINT;
  48.   gOnly1Deep:         BOOLEAN;
  49.   gOrigWDRefNum:      INTEGER;
  50.   gPBs:               TOverlappingPBs;
  51.   gSFLst:             SFTypeList;
  52.   gSysDirId:          LONGINT;
  53.   gSysVRefNum:        INTEGER;
  54.   gWDPBRec:           WDPBRec;
  55.   gZZPatImpl:         SignedByte;
  56.  
  57. {-------------------------------------------}
  58. PROCEDURE  BuildDirname;
  59. VAR
  60.   sErr:      OSErr;
  61.   sLen:      INTEGER;
  62.   sName:     Str255;
  63.   sPBs:      TOverlappingPBs;
  64. BEGIN
  65. IF  gOption[eTrace] THEN
  66.   Trace('BuildDirname');
  67. WITH sPBs,fPBRec,fCPBRec DO
  68.   BEGIN
  69.   sPBs         := gPBs;
  70.   ioNamePtr    := @sName;
  71.   ioVRefNum    := gCurrWDRefNum;
  72.   gCurrDirname := '';
  73.   IF  gHFS THEN
  74.     BEGIN
  75.     ioFDirIndex := -1;
  76.     ioDrParID   := 0;
  77.     REPEAT
  78.       ioDrDirId := ioDrParID;
  79.       sErr := PBGetCatInfo(@fCPBRec,FALSE);
  80.       IF  (sErr <> NoErr) THEN
  81.         EXIT(BuildDirname);
  82.       sLen := 
  83.         LENGTH(sName)+1+LENGTH(gCurrDirname); 
  84.       IF  (sLen <= 255) THEN
  85.         gCurrDirname := 
  86.           CONCAT(sName,':',gCurrDirname);
  87.     UNTIL ioDrDirId = 2;
  88.     END
  89.   ELSE
  90.     BEGIN
  91.     sErr := PBGetVol(@fPBRec,FALSE);
  92.     IF  (sErr = NoErr) THEN
  93.       gCurrDirname := CONCAT(sName,':');
  94.     END;
  95.   END;
  96. END;
  97. {-------------------------------------------}
  98. PROCEDURE  CallProcessFile;
  99. BEGIN
  100. gActiveSelf := 
  101.   (gCurrVRefNum  = gAppVRefNum) AND 
  102.   (gCurrDirId    = gAppDirId)   AND
  103.   (gCurrFilename = StringPtr(kCurApName)^);
  104. gActiveSys := 
  105.   (gCurrVRefNum  = gSysVRefNum) AND 
  106.   (gCurrDirId    = gSysDirId)   AND 
  107.   (gCurrFilename = StringPtr(kSysResName)^);
  108. gCurrFileDeleted := FALSE;
  109. ProcessFile;
  110. END;
  111. {-------------------------------------------}
  112. PROCEDURE  FloatWDDeeper
  113.   (pDrDirId:  LONGINT);
  114. BEGIN
  115. IF  gOption[eTrace] THEN
  116.   TraceNbr('Begin FloatWDDeeper,    WD = ',
  117.               ORD4(gCurrWDRefNum));
  118. WITH gPBs,fCPBRec DO
  119.   BEGIN
  120.   IF  NOT((pDrDirId=0) OR (pDrDirId=2)) THEN
  121.     BEGIN
  122.     gWDPBRec.ioVRefNum := gCurrWDRefNum;
  123.     gWDPBRec.ioWDDirId := 0;
  124.     gError := PBCloseWD(@gWDPBRec,FALSE);
  125.     IF  (gError <> NoErr) THEN
  126.       BEGIN
  127.       ErrorOSErr('Couldn’t close WD');
  128.       EXIT(FloatWDDeeper);
  129.       END;
  130.     END;
  131.   gWDPBRec.ioVRefNum := gCurrVRefNum;
  132.   gWDPBRec.ioWDDirId := ioDrDirId;
  133.   gError := PBOpenWD(@gWDPBRec,FALSE);
  134.   IF  (gError <> NoErr) THEN
  135.     BEGIN
  136.     ErrorOSErr('Couldn’t open subdir WD');
  137.     EXIT(FloatWDDeeper);
  138.     END;
  139.   gCurrWDRefNum := gWDPBRec.ioVRefNum;
  140.   END;
  141. IF  gOption[eTrace] THEN
  142.   TraceNbr('End   FloatWDDeeper,    WD = ',
  143.               ORD4(gCurrWDRefNum));
  144. END;
  145. {-------------------------------------------}
  146. PROCEDURE  FloatWDShallower
  147.   (pDrDirId:  LONGINT);
  148. BEGIN
  149. IF  gOption[eTrace] THEN
  150.   TraceNbr('Begin FloatWDShallower, WD = ',
  151.               ORD4(gCurrWDRefNum));
  152. WITH gPBs,fCPBRec DO
  153.   BEGIN
  154.   gError := PBCloseWD(@gWDPBRec,FALSE);
  155.   gWDPBRec.ioVRefNum := gCurrWDRefNum;
  156.   gWDPBRec.ioWDDirId := 0;
  157.   IF  (gError <> NoErr) THEN
  158.     BEGIN
  159.     ErrorOSErr('Couldn’t close subdir WD');
  160.     EXIT(FloatWDShallower);
  161.     END;
  162.   IF  (pDrDirId = 0)
  163.   OR  (pDrDirId = 2) THEN
  164.     gCurrWDRefNum := gOrigWDRefNum
  165.   ELSE
  166.     BEGIN
  167.     gWDPBRec.ioVRefNum := gCurrVRefNum;
  168.     gWDPBRec.ioWDDirId := pDrDirId;
  169.     gError := PBOpenWD(@gWDPBRec,FALSE);
  170.     IF  (gError <> NoErr) THEN
  171.       BEGIN
  172.       ErrorOSErr('Couldn’t reopen WD');
  173.       EXIT(FloatWDShallower);
  174.       END;
  175.     gCurrWDRefNum := gWDPBRec.ioVRefNum;
  176.     END;
  177.   END;
  178. IF  gOption[eTrace] THEN
  179.   TraceNbr('End   FloatWDShallower, WD = ',
  180.               ORD4(gCurrWDRefNum));
  181. END;
  182. {-------------------------------------------}
  183. PROCEDURE  GetActualDirId
  184.   (pDrDirId:  LONGINT);
  185. BEGIN
  186. WITH gPBs,fCPBRec DO
  187.   BEGIN
  188.   ioDrDirId   := pDrDirId;
  189.   ioFDirIndex := -1;
  190.   ioVRefNum   := gOrigWDRefNum;
  191.   gError := PBGetCatInfo(@fCPBRec,FALSE);
  192.   IF  (gError <> NoErr) THEN
  193.     BEGIN
  194.     ErrorOSErr('Couldn’t GetActualDirId');
  195.     EXIT(GetActualDirId);
  196.     END;
  197.   gCurrDInfo  := ioDrUsrWds;
  198.   gCurrDirId  := ioDrDirId;
  199.   IF  gOption[eTrace] THEN
  200.     TraceNbr('ActualDirID = ',gCurrDirId);
  201.   END;
  202. END;
  203. {-------------------------------------------}
  204. PROCEDURE  InitPatrols;
  205. BEGIN
  206. IF  gOption[eTrace] THEN
  207.   Trace('InitPatrols');
  208. WITH gPBs,fPBRec,fCPBRec DO
  209.   BEGIN
  210.   ZeroOutRange(@gAAPatImpl,@gZZPatImpl);
  211.   gHFS        := TWordPtr(kSFCBLen)^ > 0;
  212.  
  213.   ioNamePtr := @gCurrFilename;
  214.   IF  gHFS THEN
  215.     BEGIN
  216.     gError  := GetVRefNum
  217.       (TWordPtr(kSysMap)^,gSysVRefNum);
  218.     IF  (gError <> NoErr) THEN
  219.       ErrorOSErr('Couldn’t get act sys vol');
  220.     ioVRefNum  := gSysVRefNum;
  221.     gError     := PBHGetVInfo(@fPBRec,FALSE);
  222.     IF  (gError <> NoErr) THEN
  223.       ErrorOSErr('Couldn’t get act sys dir');
  224.     IF  (fPBRec.ioVFndrInfo[1] = 0) THEN
  225.       ErrorOSErr('Boot vol not Blessed');
  226.     gSysDirId  := ioVFndrInfo[1];
  227.     gError     := PBHGetVol(@fPBRec,FALSE);
  228.     IF  (gError <> NoErr) THEN
  229.       ErrorOSErr('Couldn’t get own DirId');
  230.     gAppDirId  := ioDirId;
  231.     gCurrDirId := ioDirId;
  232.     gCurrWDRefNum := ioVRefNum;
  233.     ioVolIndex := 0;
  234.     gError     := PBHGetVInfo(@fPBRec,FALSE);
  235.     IF  (gError <> NoErr) THEN
  236.       ErrorOSErr('Couldn’t get own VInfo');
  237.     gAppVRefNum := ioVRefNum;
  238.     END
  239.   ELSE
  240.     BEGIN
  241.     gSysVRefNum := TWordPtr(kBootDrive)^;
  242.     gError      := PBGetVol(@fPBRec,FALSE);
  243.     IF  (gError <> NoErr) THEN
  244.       ErrorOSErr('Couldn’t get own Vol');
  245.     gAppVRefNum   := ioVRefNum;
  246.     gCurrWDRefNum := ioVRefNum;
  247.     gAppDirId   := 2;
  248.     gSysDirId   := 2;
  249.     gCurrDirId  := 2;
  250.     END;
  251.   BuildDirname;
  252.   gCurrFilename := StringPtr(kCurApName)^;
  253.   ioFDirIndex   := 0;
  254.   ioDirId       := 0;
  255.   ioVRefNum     := gCurrWDRefNum;
  256.   gError        := PBGetFInfo(@fPBRec,FALSE);
  257.   IF  (gError <> NoErr) THEN
  258.     ErrorOSErr('Couldn’t get own FInfo');
  259.   gCurrFInfo    := ioFlFndrInfo;
  260.   gActiveSelf   := TRUE;
  261.   gActiveSys    := FALSE;
  262.  
  263.   gWDPBRec.ioWDProcID := $50617472; {'Patr'}
  264.   gInitdFlag    := kPatsInitd;
  265.   END;
  266. END;
  267. {-------------------------------------------}
  268. PROCEDURE  PatrolDir
  269.   (pDrDirId:  LONGINT);
  270. VAR
  271.   sIndex:    INTEGER;
  272. BEGIN
  273. IF  gOption[eTrace] THEN
  274.   TraceNbr('PatrolDir ',pDrDirId);
  275. WITH gPBs,fCPBRec DO
  276.   BEGIN
  277.   IF  (gInitdFlag <> kPatsInitd) THEN
  278.     BEGIN { shouldn't happen }
  279.     ErrorOSErr('InitPatrols not done');
  280.     EXIT(PatrolDir);
  281.     END;
  282.   IF  gHFS THEN
  283.     BEGIN
  284.     gCurrDirId := pDrDirId;
  285.     GetActualDirId(pDrDirId);
  286.     IF  (gError <> NoErr) THEN
  287.       EXIT(PatrolDir);
  288.     END
  289.   ELSE
  290.     gCurrDirId := 2;
  291.   BuildDirname;
  292.   DirectoryBegins;
  293.  
  294.   sIndex  := 1;
  295.   REPEAT
  296.     gCurrIndex  := sIndex;
  297.     ioFDirIndex := sIndex;
  298.     ioDrDirId   := 0;
  299.     ioVRefNum   := gCurrWDRefNum;
  300.     gError := PBGetFInfo(@fPBRec,FALSE);
  301.     IF  (gError = NoErr) THEN
  302.       BEGIN
  303.       gCurrFInfo  := ioFlFndrInfo;
  304.       CallProcessFile;
  305.       END
  306.     ELSE IF  (gError <> fnfErr) THEN
  307.       BEGIN
  308.       ErrorOSErr('Couldn’t get a file');
  309.       EXIT(PatrolDir);
  310.       END;
  311.     IF  NOT(gCurrFileDeleted) THEN
  312.       INC(sIndex);
  313.   UNTIL (gError <> NoErr) OR gAbortPatrol;
  314.   IF  gAbortPatrol THEN
  315.     EXIT(PatrolDir);
  316.   IF  (gError <> fnfErr) THEN
  317.     BEGIN
  318.     ErrorOSErr('Error at end of files');
  319.     EXIT(PatrolDir);
  320.     END;
  321.   gError := NoErr;
  322.  
  323.   IF  gHFS AND NOT(gOnly1Deep) THEN
  324.     BEGIN
  325.     sIndex := 1;
  326.     REPEAT
  327.       gCurrIndex  := sIndex;
  328.       ioFDirIndex := sIndex;
  329.       ioDrDirId   := 0;
  330.       ioVRefNum   := gCurrWDRefNum;
  331.       gError := PBGetCatInfo(@fCPBRec,FALSE);
  332.       IF  (gError = NoErr) THEN
  333.         BEGIN
  334.         IF  BTst(ORD4(ioFlAttrib),4) THEN
  335.           BEGIN
  336.           FloatWDDeeper (pDrDirId);
  337.           IF  (gError <> NoErr) THEN
  338.             EXIT(PatrolDir);
  339.  
  340.           PatrolDir(ioDrDirId);
  341.           IF  (gError <> NoErr)
  342.           AND (pDrDirId <> 0)
  343.           AND (pDrDirId <> 2) THEN
  344.             EXIT(PatrolDir);
  345.  
  346.           FloatWDShallower(pDrDirId);
  347.           IF  (gError <> NoErr) THEN
  348.             EXIT(PatrolDir);
  349.           END;
  350.         END
  351.       ELSE IF  (gError <> fnfErr) THEN
  352.         BEGIN
  353.         ErrorOSErr('Couldn’t get a dir');
  354.         EXIT(PatrolDir);
  355.         END;
  356.       INC(sIndex);
  357.     UNTIL (gError <> NoErr) OR gAbortPatrol;
  358.     IF  gAbortPatrol THEN
  359.       EXIT(PatrolDir);
  360.     IF  (gError <> fnfErr) THEN
  361.       BEGIN
  362.       ErrorOSErr('Error at end of subdirs');
  363.       EXIT(PatrolDir);
  364.       END;
  365.     gError := NoErr;
  366.     gCurrDirId := pDrDirId;
  367.     GetActualDirId(pDrDirId);
  368.     IF  (gError <> NoErr) THEN
  369.       EXIT(PatrolDir);
  370.     BuildDirname;
  371.     END;
  372.  
  373.   DirectoryEnds;
  374.   END;
  375. END;
  376. {-------------------------------------------}
  377. PROCEDURE  PatrolDirectories
  378.   (pOnly1Deep:BOOLEAN);
  379. BEGIN
  380. IF  gOption[eTrace] THEN
  381.   Trace('PatrolDirectories ');
  382. WITH gPBs,fPBRec,fCPBRec,gSFRep DO
  383.   BEGIN
  384.   IF  (gInitdFlag <> kPatsInitd) THEN
  385.     BEGIN { shouldn't happen }
  386.     ErrorOSErr('InitPatrols not done');
  387.     EXIT(PatrolDirectories);
  388.     END;
  389.   gOnly1Deep := pOnly1Deep;
  390.  
  391.   SFGetFile
  392.     (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  393.   WHILE good DO
  394.     BEGIN
  395.     IF  gHFS THEN
  396.       BEGIN
  397.       ioVRefNum   := gSFRep.vRefNum;
  398.       ioVolIndex  := 0;
  399.       gError  := PBHGetVInfo(@fPBRec,FALSE);
  400.       IF  (gError <> NoErr) THEN
  401.         BEGIN
  402.         ErrorOSErr('Couldn’t get own VInfo');
  403.         LEAVE;
  404.         END;
  405.       gCurrVRefNum := ioVRefNum;
  406.       END
  407.     ELSE
  408.       gCurrVRefNum := vRefNum;
  409.     gCurrWDRefNum  := vRefNum;
  410.     gOrigWDRefNum  := vRefNum;
  411.     PatrolBegins;
  412.     PatrolDir(0);
  413.     PatrolEnds;
  414.     IF  (gError <> NoErr) THEN
  415.       LEAVE;
  416.     SFGetFile
  417.       (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  418.     END;
  419.  
  420.   gError  := NoErr;
  421.   END;
  422. END;
  423. {-------------------------------------------}
  424. PROCEDURE  PatrolEverything;
  425. VAR
  426.   sIndex:    INTEGER;
  427. BEGIN
  428. IF  gOption[eTrace] THEN
  429.   Trace('PatrolEverything ');
  430. WITH gPBs,fPBRec,fCPBRec DO
  431.   BEGIN
  432.   IF  (gInitdFlag <> kPatsInitd) THEN
  433.     BEGIN { shouldn't happen }
  434.     ErrorOSErr('InitPatrols not done');
  435.     EXIT(PatrolEverything);
  436.     END;
  437.   gOnly1Deep := FALSE;
  438.   PatrolBegins;
  439.  
  440.   ioVRefNum     := 0;
  441.   sIndex        := 1;
  442.   REPEAT
  443.     gCurrIndex  := sIndex;
  444.     ioVolIndex  := sIndex;
  445.     gError      := PBGetVInfo(@fPBRec,FALSE);
  446.     IF  (gError = NoErr) THEN
  447.       BEGIN
  448.       gCurrVRefNum  := ioVRefNum;
  449.       gCurrWDRefNum := ioVRefNum;
  450.       gOrigWDRefNum := ioVRefNum;
  451.  
  452.       PatrolDir(2);
  453.  
  454.       IF  (gError <> NoErr) THEN
  455.         EXIT(PatrolEverything);
  456.       INC(sIndex);
  457.       END
  458.     ELSE IF  (gError <> nsvErr) THEN
  459.       BEGIN
  460.       ErrorOSErr('Couldn’t get a volume');
  461.       EXIT(PatrolEverything);
  462.       END;
  463.   UNTIL gError <> NoErr;
  464.   IF  (gError <> nsvErr) THEN
  465.     BEGIN
  466.     ErrorOSErr('Error at end of volumes');
  467.     EXIT(PatrolEverything);
  468.     END;
  469.  
  470.   gError  := NoErr;
  471.   PatrolEnds;
  472.   END;
  473. END;
  474. {-------------------------------------------}
  475. PROCEDURE  PatrolFiles;
  476. VAR
  477.   sPrevDirId:   LONGINT;
  478.   sPrevVRefNum: INTEGER;
  479.   sPrevWDRefNum:INTEGER;
  480.   {------------------------}
  481.   PROCEDURE  CallPrevDirEnd;
  482.   VAR
  483.     sTempDirId:   LONGINT;
  484.     sTempVRefNum: INTEGER;
  485.     sTempWDRefNum:INTEGER;
  486.   BEGIN
  487.   IF  (sPrevWDRefNum <> 0) THEN
  488.     BEGIN
  489.     sTempDirId    := gCurrDirId;
  490.     sTempVRefNum  := gCurrVRefNum;
  491.     sTempWDRefNum := gCurrWDRefNum;
  492.     gCurrDirId    := sPrevDirId;
  493.     gCurrVRefNum  := sPrevVRefNum;
  494.     gCurrWDRefNum := sPrevWDRefNum;
  495.     DirectoryEnds;
  496.     gCurrDirId    := sTempDirId;
  497.     gCurrVRefNum  := sTempVRefNum;
  498.     gCurrWDRefNum := sTempWDRefNum;
  499.     END;
  500.   END;
  501.   {------------------------}
  502. BEGIN
  503. IF  gOption[eTrace] THEN
  504.   Trace('PatrolFiles ');
  505. WITH gPBs,fPBRec,fCPBRec,gSFRep DO
  506.   BEGIN
  507.   IF  (gInitdFlag <> kPatsInitd) THEN
  508.     BEGIN { shouldn't happen }
  509.     ErrorOSErr('InitPatrols not done');
  510.     EXIT(PatrolFiles);
  511.     END;
  512.   PatrolBegins;
  513.  
  514.   sPrevWDRefNum := 0;
  515.   SFGetFile
  516.     (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  517.   WHILE good DO
  518.     BEGIN
  519.     IF  gHFS THEN
  520.       BEGIN
  521.       ioVRefNum   := gSFRep.vRefNum;
  522.       ioDrDirId   := 0;
  523.       ioFDirIndex := -1;
  524.       gError := PBGetCatInfo(@fPBRec,FALSE);
  525.       IF  (gError <> NoErr) THEN
  526.         BEGIN
  527.         ErrorOSErr('Couldn’t get DirId');
  528.         LEAVE;
  529.         END;
  530.       gCurrDirId  := ioDrDirId;
  531.       ioVolIndex  := 0;
  532.       gError := PBHGetVInfo(@fPBRec,FALSE);
  533.       IF  (gError <> NoErr) THEN
  534.         BEGIN
  535.         ErrorOSErr('Couldn’t get VInfo');
  536.         LEAVE;
  537.         END;
  538.       gCurrVRefNum := ioVRefNum;
  539.       END
  540.     ELSE
  541.       BEGIN
  542.       gCurrDirId   := 2;
  543.       gCurrVRefNum := vRefNum;
  544.       END;
  545.     gCurrFilename := fName;
  546.     gCurrIndex    := 0;
  547.     gCurrWDRefNum := vRefNum;
  548.     IF  (sPrevWDRefNum <> gCurrWDRefNum) THEN
  549.       BEGIN
  550.       CallPrevDirEnd;
  551.       BuildDirname;
  552.       DirectoryBegins;
  553.       sPrevDirId      := gCurrDirId;
  554.       sPrevVRefNum    := gCurrVRefNum;
  555.       sPrevWDRefNum   := gCurrWDRefNum;
  556.       END;
  557.     ioDrDirId   := gCurrDirId;
  558.     ioFDirIndex := gCurrIndex;
  559.     ioVRefNum   := gCurrWDRefNum;
  560.     gError := PBGetFInfo(@fPBRec,FALSE);
  561.     IF  (gError <> NoErr) THEN
  562.       BEGIN
  563.       ErrorOSErr('Couldn’t get FInfo');
  564.       LEAVE;
  565.       END;
  566.     gCurrFInfo  := ioFlFndrInfo;
  567.     CallProcessFile;
  568.     IF  gAbortPatrol THEN
  569.       LEAVE;
  570.     SFGetFile
  571.       (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  572.     END;
  573.  
  574.   gError  := NoErr;
  575.   CallPrevDirEnd;
  576.   PatrolEnds;
  577.   END;
  578. END;
  579. {*******************************************}
  580. END.